﻿// SilverlightDesktop - http://www.SilverlightDesktop.net
// Copyright (c) 2008
// by SilverlightDesktop
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.Linq;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml.Linq;

using DotNetNuke;
using DotNetNuke.Security;
using DotNetNuke.Entities.Modules;
using System.IO;
using DotNetNuke.Services.Exceptions;
using System.Web.UI.WebControls;
using System.Threading;
using System.Collections.Generic;
using ICSharpCode.SharpZipLib.Zip;

namespace SilverlightDesktop.Module
{
    public partial class ModuleAdministration : DotNetNuke.Entities.Modules.PortalModuleBase
    {
        string strAppBase = "";
        string strTempDirectory = "";
        ListItemCollection UploadMessage = new ListItemCollection();

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        #region lnkBack_Click
        protected void lnkBack_Click(object sender, EventArgs e)
        {
            Response.Redirect(DotNetNuke.Common.Globals.NavigateURL(), true);
        }
        #endregion

        #region Delete Module
        protected void ListView1_ItemDeleting(object sender, System.Web.UI.WebControls.ListViewDeleteEventArgs e)
        {
            strAppBase = Server.MapPath(this.TemplateSourceDirectory + @"\..\..\");

            //Run the uninstall script if there is one
            SilverlightDesktopDAL SilverlightDesktopDAL = new SilverlightDesktopDAL();

            // Get the selected module
            var objModule = (from Module in SilverlightDesktopDAL.SilverlightDesktopModules
                             where Module.ModuleID == Convert.ToInt32(e.Keys[0])
                             select Module).FirstOrDefault();

            if (objModule.uninstall.Trim() != "")
            {
                SilverlightDesktopDAL.ExecuteCommand(objModule.uninstall.Trim());
            }

            // Get the files for the module and delete them
            var objModules = from Modules in SilverlightDesktopDAL.SilverlightDesktopModuleFiles
                             where Modules.ModuleName.ToLower() == objModule.ModuleName.ToLower()
                             select Modules;

            foreach (var tmpModule in objModules)
            {
                string strFileToDelte = (strAppBase + "\\" + tmpModule.FileNameAndPath).Replace("\\\\", "\\");
                File.Delete(strFileToDelte);

                // Log the event
                // UploadMessage.Add(String.Format("Module: {0} - File deleted {1}.", objModules.FirstOrDefault().ModuleName, strFileToDelte));
            }

            // Delete entries in moduleFiles table
            SilverlightDesktopDAL.SilverlightDesktopModuleFiles.DeleteAllOnSubmit(objModules);
            SilverlightDesktopDAL.SubmitChanges();

        }
        #endregion

        #region Insert Module
        protected void ListView1_ItemInserted(object sender, System.Web.UI.WebControls.ListViewInsertedEventArgs e)
        {
            if (e.Exception != null)
            {
                lblModuleError.Text = e.Exception.Message;
                e.KeepInInsertMode = true;
                e.ExceptionHandled = true;
            }
        }
        #endregion

        // Module Install

        #region Install Module
        protected void btnUpload_Click(object sender, EventArgs e)
        {
            if (File1.PostedFile.FileName == "")
            {
                return;
            }

            try
            {
                SilverlightDesktopDAL SilverlightDesktopDAL = new SilverlightDesktopDAL();

                strAppBase = Server.MapPath(this.TemplateSourceDirectory + @"\..\..\");
                strTempDirectory = strAppBase + @"Temp\";

                // Create a Temp Directory
                if (Directory.Exists(strTempDirectory))
                {
                    Directory.Delete(strTempDirectory, true);
                }

                try
                {
                    Directory.CreateDirectory(strTempDirectory);
                }
                catch (Exception)
                {
                    // try again this time give the system time to delete the files first
                    Thread.Sleep(5000);
                    Directory.CreateDirectory(strTempDirectory);
                }

                string strZipFilename = File1.PostedFile.FileName;
                strZipFilename = System.IO.Path.GetFileName(strZipFilename);
                File1.PostedFile.SaveAs(strTempDirectory + strZipFilename);

                UploadMessage.Add(String.Format("File saved to {0}", strTempDirectory + strZipFilename));
                UnzipFile(strTempDirectory + strZipFilename);

                // Load the config file
                XElement doc = XElement.Load(strTempDirectory + @"\Module.config");

                string strconfigversion = doc.Element("configversion").Value;
                string strconfigtype = doc.Element("configtype").Value;
                string strmodulename = doc.Element("modulename").Value;
                string strdescription = doc.Element("description").Value;
                string strassembly = doc.Element("assembly").Value;
                string strversion = doc.Element("version").Value;
                string strclass = doc.Element("class").Value;
                string stricon = doc.Element("icon").Value;
                string strrole = doc.Element("role").Value;
                string strwindowsize = doc.Element("windowsize").Value;

                if (strconfigtype.ToLower() != "dotnetnuke module")
                {
                    UploadMessage.Add(String.Format("Attempted to install type {0}. Only ConfigType 'DotNetNuke Module' can be installed. Aborting installation.", strconfigtype));
                    CompleteModuleInstall(true);
                    return;
                    // EXIT
                }

                // **************************************************************
                // Delete files

                // Build a list of files to remove
                List<string> colFilesToRemove = new List<string>();
                foreach (XElement Element in doc.Element("removefiles").Elements())
                {
                    colFilesToRemove.Add(Element.Value);
                }

                colFilesToRemove.Sort();

                // Get the current module version if any
                int intCurrentModuleVersion = 0;
                var result = from Module in SilverlightDesktopDAL.SilverlightDesktopModules
                             where Module.ModuleName.ToLower() == strmodulename.ToLower()
                             select Module.ModuleVersion;

                intCurrentModuleVersion = (result.FirstOrDefault().ToString() == "") ? intCurrentModuleVersion : result.FirstOrDefault();

                int intModuleVersion = Convert.ToInt32(strversion.Replace(".", ""));

                if (intModuleVersion <= intCurrentModuleVersion)
                {
                    UploadMessage.Add(String.Format("Current module version is {0}. Installing module version is {1}. Aborting installation.", intCurrentModuleVersion.ToString(), intModuleVersion.ToString()));
                    CompleteModuleInstall(true);
                    return;
                    // Exit
                }
                else
                {
                    UploadMessage.Add(String.Format("Current module version is {0}. Installing module version {1}.", intCurrentModuleVersion.ToString(), intModuleVersion.ToString()));
                }

                // Get a list of all .sql scripts
                List<string> colSQLScripts = Directory.GetFiles(strTempDirectory, "*.sql").ToList();
                colSQLScripts.Sort();

                foreach (string strFile in colSQLScripts)
                {
                    string strFileName = Path.GetFileNameWithoutExtension(strFile);
                    if (strFileName.ToLower() != "uninstall")
                    {
                        int intVersion = Convert.ToInt32(strFileName.Replace(".", ""));
                        if (intVersion <= intModuleVersion)
                        {
                            try
                            {
                                string strSqlScript = GetSQLScript(strFile);
                                SilverlightDesktopDAL.ExecuteCommand(strSqlScript);
                                File.Delete(strFile);
                                UploadMessage.Add(String.Format("SQL Script processed: {0}", strFileName));
                            }
                            catch (Exception ex)
                            {
                                UploadMessage.Add(String.Format("SQL Script error in script: {0} - {1}", strFileName, ex.ToString()));
                                CompleteModuleInstall(true);
                                return;
                            }
                        }
                    }
                }

                // Update the Modules Table 

                // Delete record if it exists
                var ModuleEntry = (from Module in SilverlightDesktopDAL.SilverlightDesktopModules
                                   where Module.ModuleName.ToLower() == strmodulename.ToLower()
                                   select Module).FirstOrDefault();

                // If the Module entry does not already exist, create it
                if (ModuleEntry == null)
                {
                    ModuleEntry = new SilverlightDesktop.SilverlightDesktopModule();
                }

                ModuleEntry.AssemblyName = strassembly;
                ModuleEntry.ModuleDescription = strdescription;
                ModuleEntry.ModuleName = strmodulename;
                ModuleEntry.ClassName = strclass;
                ModuleEntry.IconName = stricon;
                ModuleEntry.Role = strrole;
                ModuleEntry.WindowSize = Convert.ToInt32(strwindowsize);
                ModuleEntry.ModuleVersion = Convert.ToInt32(strversion.Replace(".", ""));

                //Read and insert the uninstall script
                if (File.Exists(strTempDirectory + "uninstall.sql"))
                {
                    string strUninstall = GetSQLScript(strTempDirectory + "uninstall.sql");
                    ModuleEntry.uninstall = strUninstall;
                }

                // If the Module entry does not already exist insert it
                if (ModuleEntry.ModuleID == 0)
                {
                    SilverlightDesktopDAL.SilverlightDesktopModules.InsertOnSubmit(ModuleEntry);
                    UploadMessage.Add(String.Format("Created Module entry {0}", strmodulename));
                }

                SilverlightDesktopDAL.SubmitChanges();

                //Delete files
                foreach (string strDeleteFile in colFilesToRemove)
                {
                    //Remove 'Temp' from the name of the file being delted so the file is
                    //properly found
                    File.Delete(strTempDirectory.Replace(@"\Temp", "") + strDeleteFile);
                    UploadMessage.Add(String.Format("Removed File: {0}", strDeleteFile));
                }

                //Delete the .zip, .config and uninstall files
                File.Delete(strTempDirectory + strZipFilename);
                File.Delete(strTempDirectory + "uninstall.sql");
                File.Delete(strTempDirectory + "Module.config");

                //Delete any file details in the database
                var colModuleFiles = from ModuleFiles in SilverlightDesktopDAL.SilverlightDesktopModuleFiles
                                     where ModuleFiles.ModuleName.ToLower() == strmodulename.ToLower()
                                     select ModuleFiles;

                SilverlightDesktopDAL.SilverlightDesktopModuleFiles.DeleteAllOnSubmit(colModuleFiles);
                SilverlightDesktopDAL.SubmitChanges();

                //Add The Module File information to the database

                List<string> colFiles = Utility.GetAllFileNames(strTempDirectory).ToList();
                foreach (string strFile in colFiles)
                {
                    SilverlightDesktopModuleFile objModuleFile = new SilverlightDesktopModuleFile();
                    objModuleFile.ModuleName = strmodulename.ToLower();
                    objModuleFile.FileNameAndPath = Path.GetFullPath(strFile).ToString().Replace(strTempDirectory, "");
                    SilverlightDesktopDAL.SilverlightDesktopModuleFiles.InsertOnSubmit(objModuleFile);
                    SilverlightDesktopDAL.SubmitChanges();

                    try
                    {
                        // Move the file to it's destination
                        File.Move(strFile, strFile.Replace(@"\Temp", ""));
                    }
                    catch
                    {
                        UploadMessage.Add(String.Format("File already exists: {0}", strFile.Replace(@"\Temp", "")));
                        // Delete the file instead
                        File.Delete(strFile);
                    }
                }

                // Cleanup
                Directory.Delete(strTempDirectory, true);
                UploadMessage.Add(String.Format("Temp directory removed"));
                CompleteModuleInstall(false);
            }
            catch (Exception ex)
            {
                UploadMessage.Add(ex.Message);
                CompleteModuleInstall(true);
            }
        }

        #endregion

        #region UnzipFile
        private void UnzipFile(string strZipFile)
        {
            using (ZipInputStream s = new ZipInputStream(File.OpenRead(strZipFile)))
            {
                ZipEntry theEntry;
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    string directoryName = Path.GetDirectoryName(strTempDirectory + theEntry.Name);
                    string fileName = Path.GetFileName(strTempDirectory + theEntry.Name);

                    // create directory
                    if (directoryName.Length > 0)
                    {
                        if (!Directory.Exists(directoryName))
                        {
                            Directory.CreateDirectory(directoryName);
                            UploadMessage.Add(String.Format("Directory Created {0}", directoryName));
                        }
                    }

                    if (fileName != String.Empty)
                    {
                        using (FileStream streamWriter = File.Create(strTempDirectory + theEntry.Name))
                        {
                            UploadMessage.Add(String.Format("File Unzipped: {0}", theEntry.Name));
                            int size = 2048;
                            byte[] data = new byte[2048];
                            while (true)
                            {
                                size = s.Read(data, 0, data.Length);
                                if (size > 0)
                                {
                                    streamWriter.Write(data, 0, size);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #region GetSQLScript
        private String GetSQLScript(string PathandScript)
        {
            string strSQLScript;
            StreamReader reader = new StreamReader(PathandScript);
            strSQLScript = reader.ReadToEnd();
            reader.Close();
            reader = null;
            return strSQLScript;
        }
        #endregion        

        #region CompleteModuleInstall
        private void CompleteModuleInstall(bool HasErrors)
        {
            // Refresh the module list
            ListView1.DataBind();

            if (HasErrors)
            {
                ErrorListBox.Visible = true;
                foreach (ListItem strUploadMessage in UploadMessage)
                {                    
                    ErrorListBox.Items.Add(strUploadMessage.Value);
                }

                // Cleanup
                Directory.Delete(strTempDirectory, true);
                ErrorListBox.Items.Add(String.Format("Temp directory removed"));
            }
        }
        #endregion
}
}